﻿/// <reference path="TsLinq.d.ts" />
/// <reference path="Linq.ts" />
/// <reference path="DefaultComparer.ts" />

//
//  Implementation for the Timespan C# class.
//
class Timespan {
    private msecPerSecond: number = 1000;
    private msecPerMinute: number = 60000;
    private msecPerHour: number = 3600000;
    private msecPerDay: number = 86400000;

    // Internally we store the TimeSpan as Milliseconds
    ms: number = 0;

    //  
    //  Constructor for the timespan class.
    //
    constructor(milliseconds?: number, seconds?: number, minutes?: number, hours?: number, days?: number){
        this.addDays(days);
        this.addHours(hours);
        this.addMinutes(minutes);
        this.addSeconds(seconds);
        this.addMilliseconds(milliseconds);
    }

    //
    //  Adds the given value of days.
    //
    addDays(days: number): Timespan {
        if (!this.isNumeric(days)) {
            return;
        }
        this.ms += (days * this.msecPerDay);
        return this;
    }

    //
    //  Adds the given range of hours.
    //
    addHours(hours: number): Timespan {
        if (!this.isNumeric(hours)) {
            return;
        }
        this.ms += (hours * this.msecPerHour);
        return this;
    }

    //
    //  Adds the given range of minutes.
    //
    addMinutes(minutes: number): Timespan {
        if (!this.isNumeric(minutes)) {
            return;
        }
        this.ms += (minutes * this.msecPerMinute);
        return this;
    }

    //
    //  Adds the given count of miliseconds.
    //
    addMilliseconds(milliseconds): Timespan {
        if (!this.isNumeric(milliseconds)) {
            return;
        }
        this.ms += milliseconds;
        return this;
    }

    //
    //  Adds the given numbers of seconds.
    //
    addSeconds(seconds: number): Timespan {
        if (!this.isNumeric(seconds)) {
            return;
        }
        this.ms += (seconds * this.msecPerSecond);
        return this;
    }

    //
    //  Subtracts the given value of days.
    //
    subtractDays(days: number): Timespan {
        if (!this.isNumeric(days)) {
            return;
        }
        this.ms -= (days * this.msecPerDay);
        return this;
    }

    //
    //  Subtracts the given range of hours.
    //
    subtractHours(hours: number): Timespan {
        if (!this.isNumeric(hours)) {
            return;
        }
        this.ms -= (hours * this.msecPerHour);
        return this;
    }

    //
    //  Subtracts the given range of minutes.
    //
    subtractMinutes(minutes: number): Timespan {
        if (!this.isNumeric(minutes)) {
            return;
        }
        this.ms -= (minutes * this.msecPerMinute);
        return this;
    }

    //
    //  Subtracts the given count of miliseconds.
    //
    subtractMilliseconds(milliseconds): Timespan {
        if (!this.isNumeric(milliseconds)) {
            return;
        }
        this.ms -= milliseconds;
        return this;
    }

    //
    //  Subtracts the given numbers of seconds.
    //
    subtractSeconds(seconds: number): Timespan {
        if (!this.isNumeric(seconds)) {
            return;
        }
        this.ms -= (seconds * this.msecPerSecond);
        return this;
    }

    //
    //  Helper method.
    //
    isNumeric(input: any): boolean {
        return input!==undefined && !isNaN(parseFloat(input)) && isFinite(input);
    }

    //
    //  Adds the given timespan
    //
    add(ts: Timespan): Timespan {
        if (!(ts instanceof Timespan)) {
            return;
        }
        this.ms += ts.totalMilliseconds();
        return this;
    }

    //
    //  Adds the given timespan
    //
    subtract(ts: Timespan): Timespan {
        if (!(ts instanceof Timespan)) {
            return;
        }
        this.ms -= ts.totalMilliseconds();
        return this;
    }

    //
    //  Returns an value wherever the two timespan are equal.
    //
    equals = function (ts: Timespan): boolean {
        if (!(ts instanceof Timespan)) {
            return false;
        }
        return this.ms === ts.totalMilliseconds();
    }

    //
    //  Returns an value of the total milliseconds of the given timerange.
    //
    totalMilliseconds = function (roundDown: boolean = false): number {
        var result = this.ms;
        if (roundDown === true) {
            result = Math.floor(result);
        }
        return result;
    }

    //
    //  Returns an value of the total seconds of the given timerange.
    //
    totalSeconds = function (roundDown: boolean = false): number {
        var result = this.ms / this.msecPerSecond;
        if (roundDown === true) {
            result = Math.floor(result);
        }
        return result;
    }

    //
    //  Returns an value of the total minutes of the given timerange.
    //
    totalMinutes = function (roundDown: boolean = false): number {
        var result = this.ms / this.msecPerMinute;
        if (roundDown === true) {
            result = Math.floor(result);
        }
        return result;
    }

    //
    //  Returns an value of the total hours of the given timerange.
    //
    totalHours = function (roundDown: boolean = false): number {
        var result = this.ms / this.msecPerHour;
        if (roundDown === true) {
            result = Math.floor(result);
        }
        return result;
    }

    //
    //  Returns an value of the total days of the given timerange.
    //
    totalDays = function (roundDown: boolean = false): number {
        var result = this.ms / this.msecPerDay;
        if (roundDown === true) {
            result = Math.floor(result);
        }
        return result;
    }

    //
    //  Returns the fraction of milliseconds.
    //
    milliseconds(): number {
        return this.ms;
    }

    //
    //  Returns the fraction of seconds.
    //
    seconds(): number {
        return Math.floor(this.ms / this.msecPerSecond) % 60;
    }

    //
    //  Returns the fraction of minutes.
    //
    minutes(): number {
        return Math.floor(this.ms / this.msecPerMinute) % 60;
    }

    //
    //  Returns the fraction of hours.
    //
    hours(): number {
        return Math.floor(this.ms / this.msecPerHour) % 24
    }

    //
    //  Returns the fraction of days.
    //
    days(): number {
        return Math.floor(this.ms / this.msecPerDay);
    }

    //
    //  Static constructor.
    //
    static fromMilliseconds(milliseconds: number): Timespan {
        return new Timespan(milliseconds);
    }

    //
    //  Static constructor.
    //
    static fromSeconds(seconds: number): Timespan {
        return new Timespan(0, seconds);
    }

    //
    //  Static constructor.
    //
    static fromMinutes(minutes: number): Timespan {
        return new Timespan(0, 0, minutes);
    }

    //
    //  Static constructor.
    //
    static fromHours(hours: number): Timespan {
        return new Timespan(0, 0, 0, hours);
    }

    //
    //  Static constructor.
    //
    static fromDays(days: number): Timespan {
        return new Timespan(0, 0, 0, 0, days);
    }
}